import 'dart:convert';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart';
import 'package:url_launcher/url_launcher.dart';

import '../../../modules/config/jd_enum.dart';
import '../../../modules/navigator/navigator_util.dart';
import '../../../modules/widgets/hint_dialog.dart';
import '../../router/router_util.dart';
import '../../utils/jd_log.dart';
import '../../utils/string_tool.dart';
import '../basic/jd_app_bar.dart';
import '../image/jd_network_image.dart';

const kFlutterAssetsPrefix = 'flutterAssets://';

typedef YouthJavaScriptHandlerCallback = Future<Map<String, dynamic>> Function(
    BuildContext context, Map<String, dynamic> params);

final kGlobalJavaScriptHandler = <String, YouthJavaScriptHandlerCallback>{};

class WebViewPage extends StatefulWidget {
  final Map<String, dynamic> params;

  const WebViewPage({Key? key, required this.params}) : super(key: key);

  String get url => StringTool.toStringOrEmpty(params['url']);

  /// null:auto
  String? get title => params['title'] as String?;

  @override
  State<StatefulWidget> createState() => WebViewState();
}

class WebViewState extends State<WebViewPage> {
  late final _currentTitle = ValueNotifier(widget.title ?? '');
  final _currentProgress = ValueNotifier(0.0);
  final _webViewOptions = InAppWebViewGroupOptions(
    crossPlatform: InAppWebViewOptions(
      useOnDownloadStart: true,
      useShouldOverrideUrlLoading: true,
      mediaPlaybackRequiresUserGesture: false,
    ),
    android: AndroidInAppWebViewOptions(
      useHybridComposition: true,
    ),
    ios: IOSInAppWebViewOptions(
      allowsInlineMediaPlayback: true,
    ),
  );

  InAppWebViewController? _webViewController;

  bool _canGoBack = false;
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: JDAppBar(
        titleNotifier: _currentTitle,
        leftWidget: _canGoBack
            ? BackButtonWrap(
                backButtonType: PageCloseButtonType.closeBlack,
                callBack: () async {
                  if (await _webViewController?.canGoBack() == true) {
                    _webViewController?.goBack();
                  } else {
                    NavigatorUtil.maybePop(context);
                  }
                },
              )
            : Gap.empty,
      ),
      body: _buildContent(),
    );
  }

  Widget _buildContent() {
    final url = widget.url;
    if (url.isEmpty) return const SizedBox();
    if (url.startsWith(kFlutterAssetsPrefix) == true) {
      return _buildFutureWebView(url);
    }
    return _buildWebView(Uri.parse(url));
  }

  FutureBuilder _buildFutureWebView(String url) {
    return FutureBuilder<Uri>(
      future: () async {
        final fileContent = await rootBundle
            .loadString(url.replaceAll(kFlutterAssetsPrefix, ''));
        return Uri.dataFromString(fileContent,
            mimeType: 'text/html', encoding: Encoding.getByName('utf-8'));
      }(),
      builder: (BuildContext context, AsyncSnapshot<Uri> snapshot) {
        return _buildWebView(snapshot.data!);
      },
    );
  }

  Widget _buildWebView(Uri uri) {
    return Stack(children: [
      InAppWebView(
        key: ValueKey('WebViewState#$hashCode'),
        initialUrlRequest: URLRequest(url: uri),
        initialOptions: _webViewOptions,
        onWebViewCreated: (controller) {
          _printLog('onWebViewCreated', shortHash(controller.hashCode));
          _webViewController = controller;
          // window.flutter_inappwebview.callHandler('close_window').then(function(result) {
          //   console.log(result); // {message: {'success':1}, messageLevel: 1}
          // });
          controller.addJavaScriptHandler(
            handlerName: 'close_window',
            callback: (args) async {
              await RouterUtil.pop(context);
              return {'success': 1};
            },
          );
          kGlobalJavaScriptHandler.forEach((key, value) {
            _printLog('addJavaScriptHandler', key);
            controller.addJavaScriptHandler(
              handlerName: key,
              callback: (args) async {
                final params =
                    args[0] is Map ? args[0] : json.decode('${args[0]}');
                _printLog(
                    'callJavaScriptHandler', '$key,${json.encode(params)}');
                return value.call(
                    context,
                    Map<String, dynamic>.of(
                        args[0] is Map ? args[0] : json.decode('${args[0]}')));
              },
            );
          });
        },
        onTitleChanged: (controller, title) async {
          final url = (await controller.getUrl()).toString();
          _printLog('onTitleChanged', '$title, $url');

          // 固定标题
          if (StringTool.isNotEmpty(widget.title)) return;
          _currentTitle.value = title ?? _currentTitle.value;
        },
        onLoadStart: (controller, url) {
          _printLog('onLoadStart', '$url');
        },
        onLoadStop: (controller, url) async {
          _printLog('onLoadStop', '$url');
          _webViewController?.canGoBack().then((value) {
            setState(() {
              _canGoBack = value;
            });
          });
        },
        onLoadError: (controller, url, code, message) {
          _printLog('onLoadError', '$url, $code, $message');
          _webViewController?.canGoBack().then((value) {
            setState(() {
              _canGoBack = value;
            });
          });
        },
        onLoadHttpError: (controller, url, code, message) {
          _printLog('onLoadHttpError', '$url, $code, $message');
        },
        onLoadResource: (controller, resource) {
          _printLog('onLoadResource', '$resource');
        },
        onLoadResourceCustomScheme: (controller, resource) async {
          _printLog('onLoadResourceCustomScheme', '$resource');
          return null;
        },
        onJsAlert: (controller, resource) async {
          _printLog('onJsAlert', '$resource');
          return null;
        },
        onJsConfirm: (controller, resource) async {
          _printLog('onJsConfirm', '$resource');
          return null;
        },
        onJsPrompt: (controller, resource) async {
          _printLog('onJsPrompt', '$resource');
          return null;
        },
        onProgressChanged: (controller, progress) {
          _currentProgress.value = progress / 100.0;
        },
        onConsoleMessage: (controller, consoleMessage) {
          _printLog('onConsoleMessage', '$consoleMessage');
        },
        onDownloadStartRequest: (controller, url) {
          _currentProgress.value = 1;
          HintDialog(
            content: '是否下载当前文件\n${url.toString().split('?').first}',
            leftButtonFunction: (context) {
              Navigator.pop(context);
            },
            rightButtonFunction: (context) {
              Navigator.pop(context);
            },
          ).show(context);
        },
        androidOnPermissionRequest: (controller, origin, resources) async {
          return PermissionRequestResponse(
              resources: resources,
              action: PermissionRequestResponseAction.GRANT);
        },
        shouldOverrideUrlLoading: (controller, navigationAction) async {
          final uri = navigationAction.request.url!;
          _printLog('shouldOverrideUrlLoading', '$uri');
          if (![
            'http',
            'https',
            'file',
            'chrome',
            'data',
            'javascript',
            'about'
          ].contains(uri.scheme)) {
            if (await canLaunchUrl(uri)) {
              hintShow(uri);
            }
            return NavigationActionPolicy.CANCEL;
          } else if (['http', 'https'].contains(uri.scheme)) {
            final url = (await controller.getUrl()).toString();
          }
          return NavigationActionPolicy.ALLOW;
        },
      ),
      ValueListenableBuilder(
        valueListenable: _currentProgress,
        builder: (BuildContext context, double value, Widget? child) {
          return Visibility(
            visible: value != 1,
            child: LinearProgressIndicator(
                value: value,
                minHeight: 2,
                valueColor: AlwaysStoppedAnimation<Color>(
                    (Colors.black.withOpacity(0.5)))), // 进度条的颜色,),
          );
        },
      )
    ]);
  }

  hintShow(Uri uri) {
    HintDialog(
      content: '即将打开其他应用',
      leftButtonFunction: (context) {
        Navigator.pop(context);
      },
      rightButtonFunction: (context) {
        Navigator.pop(context);
        launchUrl(uri);
      },
    ).show(context);
  }

  _printLog(String tag, String message) {
    jdLog('webview-----tag $tag  message--- $message');
  }
}
